﻿using DiLe.Mes.Application.Cloud.Dashboard;
using DiLe.Mes.Application.Cloud.Statistics;
using DiLe.Mes.Application.Common;
using DiLe.Mes.Application.Common.Equipment;
using DiLe.Mes.Application.Common.Mould;
using DiLe.Mes.Cloud.Controllers.Dashboard.Dto;
using DiLe.Mes.Cloud.Controllers.Statistics.Dto;
using DiLe.Mes.Model.Cloud.Dashboard.Statistics;
using DiLe.Mes.Model.Cloud.Statistics;
using DiLe.Mes.Model.Common.Equipment.Entity.Manage;
using DiLe.Mes.Service.Dto;

namespace DiLe.Mes.Cloud.Controllers.Dashboard {
    /// <summary>
    /// 生产Dashboard
    /// </summary>
    [ApiExplorerSettings(GroupName = ApiCloudGroupConst.Dashboard)]
    public class ProductionDashboardController : ApiBaseController {

        private readonly EquipmentDashboardClient _equipmentDashboardClient;
        private readonly EquipmentManageClient _equipmentclient;
        private readonly APPClient _appclient;
        private readonly StatisticsClient _statistics;
        private readonly WorkOrderClient _workOrder;
        private readonly MouldInfoClient _mouldInfoClient;
        /// <summary>
        /// 
        /// </summary>
        public ProductionDashboardController(EquipmentDashboardClient equipmentDashboardClient,
                                             EquipmentManageClient equipmentManageClient,

                                             WorkOrderClient workOrderClient,
                                             MouldInfoClient mouldInfoClient,
                                             APPClient appclient,
                                             StatisticsClient statisticsClient) {
            _equipmentDashboardClient = equipmentDashboardClient;
            _equipmentclient = equipmentManageClient;
            _workOrder = workOrderClient;
            _mouldInfoClient = mouldInfoClient;
            _appclient = appclient;
            _statistics = statisticsClient;
        }

        /// <summary>
        /// 获取生产Dashboard
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<ApiResult<ProductionDashboardDto>> GetProductionDashboard() {
            var dto = new ProductionDashboardDto();
            long orgid = AppHelper.QueryOrgId;

            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList(orgid);
            var day = DateTime.Now.Date;
            if (DateTime.Now.Hour < 8) {
                day = DateTime.Now.AddDays(-1).Date;
            }

            var eqswhereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            eqswhereExp.And(p => p.Date == day);
            eqswhereExp.And(p => p.FactoryId == orgid);
            var eqstatistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(eqswhereExp.ToExpression());


            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date == day);
            whereExp.And(p => p.FactoryId == orgid);
            var eosstatistics = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());


            #region AOI/CCD
            //AOI
            var aoires = GetAOIStatisticsDto(infoList, eosstatistics, dic);
            dto.AOIYieldRateDto = aoires.Item1;
            dto.AOIBadRateDto = aoires.Item2;
            dto.AOIInspectionDto = aoires.Item3;

            dto.AOIUtilizationRateDto = GetUtilizationRateDto("AOI", infoList, eqstatistics, dic, typeList);
            #endregion

            #region 成型机
            dto.OutputDto = GetOutputDto(infoList, eosstatistics, dic);
            dto.UtilizationRateDto = GetUtilizationRateDto("成型机", infoList, eqstatistics, dic, typeList);
            dto.UsageRateDto = GetUsageRateDto(infoList, eqstatistics, dic, typeList, day, day);
            #endregion


            //切箍边
            dto.TrimOutputDto = GetTrimOutputDto(infoList, eosstatistics, dic);
            dto.TrimUtilizationRateDto = GetUtilizationRateDto("冲切机", infoList, eqstatistics, dic, typeList);



            //堆叠机
            dto.StackingOutputDto = GetStackingOutputDto(infoList, eosstatistics, dic);

            //订单数量
            //dto.CumulativeOrderQuantityDto = await GetCumulativeOrderQuantityDto();
            //入库数量
            //dto.CumulativeStockInQuantityDto = await GetCumulativeStockInQuantityDtoAsync(infoList, dic, dto.CumulativeOrderQuantityDto);
            return Success(dto);
        }

        #region AOI良率
        /// <summary>
        /// 获取AOI良率
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<AOIYieldRateDto>> GetAOIYieldRate(StatisticsParameter parameter) {

            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);

            long orgid = AppHelper.QueryOrgId;
            List<EquipmentInfoModel> infoList = await _equipmentclient.GetEquipmentInfoModelListAsync(orgid);


            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            var dataList = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());

            var items = GetAOIYieldRateStatisticsModels(infoList, dataList, dic);
            var aoiyieldratedto = new AOIYieldRateDto {
                Items = items,
                Total = 0
            };
            var total = items.Sum(x => x.InspectionQuantity);
            if (total>0) {
                aoiyieldratedto.Total = Math.Round((decimal)items.Sum(x => x.YieldQuantity) / total * 100, 1);
            }

            return Success(aoiyieldratedto);
        }
        /// <summary>
        /// 获取AOI不良率
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<AOIBadRateDto>> GetAOIBadRate(StatisticsParameter parameter) {

            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList();
            long orgid = AppHelper.QueryOrgId;
            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);

            var dataList = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());

            var items = GetAOIYieldRateStatisticsModels(infoList, dataList, dic);
            var aoibadratedto = new AOIBadRateDto {
                Items = items,
                Total = Math.Round((decimal)items.Sum(x => x.NGNumber ?? 0) / items.Sum(x => x.InspectionQuantity) * 100, 1)
            };
            return Success(aoibadratedto);
        }
        /// <summary>
        /// 获取检验量
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<AOIInspectionDto>> GetAOIInspectionDto(StatisticsParameter parameter) {

            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList();
            long orgid = AppHelper.QueryOrgId;
            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);
            var dataList = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());

            var items = GetAOIYieldRateStatisticsModels(infoList, dataList, dic);
            //检验量
            var aoiinspectiondto = new AOIInspectionDto {
                Items = items,
                Total = items.Sum(x => x.InspectionQuantity)
            };
            return Success(aoiinspectiondto);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static (AOIYieldRateDto, AOIBadRateDto, AOIInspectionDto) GetAOIStatisticsDto(List<EquipmentInfoModel> infos,
                                                          List<EquipmentOutputStatisticsEntity> statisticslist,
                                                          Dictionary<string, List<long>> dic) {
            var items = GetAOIYieldRateStatisticsModels(infos, statisticslist, dic);
            decimal inspectionQuantity = items.Sum(x => x.InspectionQuantity) * 100;
            decimal yieldquantity = items.Sum(x => x.YieldQuantity) * 100;
            //良率
            var aoiyieldratedto = new AOIYieldRateDto {
                Items = items,
                Total = 0
            };
            if (inspectionQuantity > 0) {
                aoiyieldratedto.Total = Math.Round(yieldquantity / inspectionQuantity, 1);
            }

            //不良率
            decimal NGNumber = items.Sum(x => x.NGNumber ?? 0);
            var aoibadratedto = new AOIBadRateDto {
                Items = items,
                Total = 0
            };
            if (inspectionQuantity > 0) {
                aoibadratedto.Total = Math.Round(NGNumber / inspectionQuantity, 1);
            }

            //检验量
            var aoiinspectiondto = new AOIInspectionDto {
                Items = items,
                Total = inspectionQuantity
            };
            return (aoiyieldratedto, aoibadratedto, aoiinspectiondto);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static List<AOIYieldRateStatisticsModel> GetAOIYieldRateStatisticsModels(List<EquipmentInfoModel> infos,
                                                                                         List<EquipmentOutputStatisticsEntity> statisticslist,
                                                                                         Dictionary<string, List<long>> dic) {
            var list = dic["AOI"];
            var items = new List<AOIYieldRateStatisticsModel>();
            int index = 0;
            foreach (var info in infos) {
                if (info == null || !list.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var eslist = statisticslist.Where(x => x.EquipmentCode == info.EquipmentCode).ToList();
                if (eslist.None()) {
                    continue;
                }
                var m = new AOIYieldRateStatisticsModel {
                    EquipmentName = info.EquipmentName,
                    EquipmentCode = info.EquipmentCode,
                    NGNumber = 0,
                    Id = index++
                };
                items.Add(m);
                foreach (var item in eslist) {
                    int ngnum = item.EndCheckNG - item.StartCheckNG ?? 0;
                    int num = item.EndNumber - item.StartNumber ?? 0;
                    m.NGNumber += ngnum;
                    m.InspectionQuantity += num;
                    if (num > 0) {
                        m.YieldQuantity += num - ngnum;
                    }
                }
                if (m.InspectionQuantity > 0) {
                    m.AOIYieldRate = Math.Round((decimal)(m.InspectionQuantity - m.NGNumber) / m.InspectionQuantity * 100, 1);
                }
                if (m.NGNumber > 0) {
                    m.AOIBadRate = Math.Round((decimal)m.NGNumber / m.InspectionQuantity * 100, 1);
                }
            }
            var datalist = items.OrderBy(x => x.EquipmentName).ToList();
            return datalist;
        }
        /// <summary>
        /// 获取AOI良率
        /// </summary>
        /// <returns></returns>
        private static AOIYieldRateDto GetAOIYieldRate(List<AOIYieldRateStatisticsEntity> dataList) {
            var dto = new AOIYieldRateDto();
            var items = new List<AOIYieldRateStatisticsModel>();
            var maps = dataList.GroupBy(x => x.EquipmentName).Select(x => (x.Key, x.ToList())).ToList();
            int index = 0;
            foreach (var (key, list) in maps) {
                var m = new AOIYieldRateStatisticsModel {
                    Id = index++,
                    EquipmentName = list.FirstOrDefault()?.EquipmentName ?? "",
                    EquipmentCode = list.FirstOrDefault()?.EquipmentCode ?? "",
                    NGNumber = 0
                };
                foreach (var item in list) {
                    m.NGNumber += item.EndCheckNGNo - item.StartCheckNGNo;
                    m.InspectionQuantity += (item.EndCheckTimes ?? 0) - item.StartCheckTimes;
                }
                if (m.InspectionQuantity > 0) {
                    m.YieldQuantity = m.InspectionQuantity - (m.NGNumber ?? 0);
                    m.AOIYieldRate = Math.Round(m.YieldQuantity / (decimal)m.InspectionQuantity * 100, 1);
                    items.Add(m);
                }
            }
            dto.Items = items.OrderBy(x => x.EquipmentCode).ToList();
            var c1_sum = items.Sum(p => p.YieldQuantity);
            var c2_sum = items.Sum(p => p.InspectionQuantity);
            dto.Total = Math.Round(c1_sum / (decimal)c2_sum * 100, 1);
            return dto;
        }

        /// <summary>
        /// 获取AOI推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<AOIYieldRateStatisticsModel>>> GetAOIRunChart(RunChartParameter parameter) {
            var list = new List<AOIYieldRateStatisticsModel>();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);

            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(x => x.EquipmentCode == parameter.EquipmentCode);
            var dataList = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());
            list = GetAOIYieldRateList(dataList);
            return Success(list);
        }
        /// <summary>
        /// 获取AOI良率
        /// </summary>
        /// <returns></returns>
        private static List<AOIYieldRateStatisticsModel> GetAOIYieldRateList(List<EquipmentOutputStatisticsEntity> dataList) {

            var items = new List<AOIYieldRateStatisticsModel>();
            var maps = dataList.GroupBy(x => x.Date).Select(x => (x.Key, x.ToList())).ToList();
            int index = 0;
            foreach (var (key, list) in maps) {

                var m = new AOIYieldRateStatisticsModel {
                    Id = index,
                    CheckDate = key,
                    EquipmentName = list.FirstOrDefault()?.EquipmentName ?? "",
                    EquipmentCode = list.FirstOrDefault()?.EquipmentCode ?? "",
                    NGNumber = 0
                };
                foreach (var item in list) {
                    m.NGNumber += item.EndCheckNG - item.StartCheckNG;
                    m.InspectionQuantity += item.EndNumber - item.StartNumber ?? 0;
                }
                if (m.InspectionQuantity > 0) {
                    m.YieldQuantity = m.InspectionQuantity - (m.NGNumber ?? 0);
                    m.AOIYieldRate = Math.Round(m.YieldQuantity / (decimal)m.InspectionQuantity * 100, 1);
                    m.AOIBadRate = Math.Round((m.NGNumber ?? 0) / (decimal)m.InspectionQuantity * 100, 1);
                    items.Add(m);
                }
                index++;
            }
            return items;
        }


        /// <summary>
        /// 获取所有AOI推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<AOIYieldRateRunChartDto>>> GetAllAOIRunChart(RunChartParameter parameter) {
            var dtoList = new List<AOIYieldRateRunChartDto>();
            var infoList = _equipmentclient.GetEquipmentInfoModelList();
            var list = new List<AOIYieldRateStatisticsModel>();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);

            long orgid = AppHelper.QueryOrgId;

            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);

            var dataList = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());
            var typeids = dic["AOI"];

            var maps = dataList.GroupBy(x => x.Date).Select(x => (x.Key, x.ToList())).ToList();
            var items = new List<AOIYieldRateStatisticsModel>();
            int index = 0;
            foreach (var (key, maplist) in maps) {
                var m = new AOIYieldRateStatisticsModel {
                    Id = index++,
                    CheckDate = key,
                    NGNumber = 0
                };
                foreach (var data in maplist) {
                    var info = infoList.FirstOrDefault(x => x.EquipmentCode == data.EquipmentCode);
                    if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                        continue;
                    }
                    m.NGNumber += data.EndCheckNG - data.StartCheckNG;
                    m.InspectionQuantity += data.EndNumber - data.StartNumber ?? 0;
                }
                if (m.InspectionQuantity > 0) {
                    m.YieldQuantity = m.InspectionQuantity - (m.NGNumber ?? 0);
                    m.AOIYieldRate = Math.Round(m.YieldQuantity / (decimal)m.InspectionQuantity * 100, 1);
                    m.AOIBadRate = Math.Round((m.NGNumber ?? 0) / (decimal)m.InspectionQuantity * 100, 1);
                    items.Add(m);
                }
            }
            var dto = new AOIYieldRateRunChartDto() {
                EquipmentCode = "",
                EquipmentName = "",
                DataList = items
            };
            dtoList.Add(dto);
            return Success(dtoList);
        }
        #endregion
        #region 产出
        /// <summary>
        /// 成型制程产出
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<EquipmentOutputDto>> GetOutputDto(StatisticsParameter parameter) {
            var dto = new EquipmentOutputDto();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            long orgid = AppHelper.QueryOrgId;
            var infoList = _equipmentclient.GetEquipmentInfoModelList(orgid);

            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);
            var eosstatistics = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());
            if (parameter.Type == "FORMING") {
                dto = GetOutputDto(infoList, eosstatistics, dic);
            } else if (parameter.Type == "TRIM") {
                dto = GetTrimOutputDto(infoList, eosstatistics, dic);
            } else if (parameter.Type == "STACKING") {
                dto = GetStackingOutputDto(infoList, eosstatistics, dic);
            }
            return Success(dto);
        }

        /// <summary>
        /// 成型制程产出
        /// </summary>
        /// <returns></returns>
        private EquipmentOutputDto GetOutputDto(List<EquipmentInfoModel> infos,
                                                List<EquipmentOutputStatisticsEntity> outputStatisticsList,
                                                Dictionary<string, List<long>> dic) {
            var dto = new EquipmentOutputDto();
            var typeids = dic["成型机"];
            int index = 0;
            var items = new List<EquipmentOutputStatisticsModel>();
            var maps = outputStatisticsList.GroupBy(x => x.EquipmentCode).Select(x => (x.Key, x.ToList())).ToList();
            foreach (var (key, list) in maps) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == key);
                if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var data = list.FirstOrDefault();
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;
                foreach (var item in list) {
                    if (item.EndMouldNumber > 0) {
                        m.MouldTimes += item.EndMouldNumber - item.StartMouldNumber ?? 0;
                    }
                }
                m.MouldCavityNum = 80;
                m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                items.Add(m);
            }
            dto.Items = [.. items.OrderBy(x => x.EquipmentName)];
            var others = GetOtherOutputDto(infos, outputStatisticsList, dic, ref index);
            if (!others.None()) {
                dto.Items.AddRange(others);
            }
            dto.Total = items.Sum(p => p.OutputQuantity);
            return dto;
        }
        /// <summary>
        /// 成型制程产出-1311
        /// </summary>
        /// <returns></returns>
        private List<EquipmentOutputStatisticsModel> GetOtherOutputDto(List<EquipmentInfoModel> infos,
                                                                        List<EquipmentOutputStatisticsEntity> outputStatisticsList,
                                                                        Dictionary<string, List<long>> dic,
                                                                        ref int index) {

            var typeids = dic["生产线"];
            var items = new List<EquipmentOutputStatisticsModel>();
            var maps = outputStatisticsList.GroupBy(x => x.EquipmentCode).Select(x => (x.Key, x.ToList())).ToList();
            foreach (var (key, list) in maps) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == key);
                if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var data = list.FirstOrDefault();
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;
                foreach (var item in list) {
                    if (item.EndMouldNumber > 0) {
                        m.MouldTimes += item.EndMouldNumber - item.StartMouldNumber ?? 0;
                    }
                }
                m.MouldCavityNum = 112;
                m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                items.Add(m);
            }

            return items;
        }

        /// <summary>
        /// 切边机
        /// </summary>
        /// <returns></returns>
        private static EquipmentOutputDto GetTrimOutputDto(List<EquipmentInfoModel> infos,
                                                           List<EquipmentOutputStatisticsEntity> outputStatisticsList,
                                                           Dictionary<string, List<long>> dic) {
            var dto = new EquipmentOutputDto();
            var typeids = dic["冲切机"];
            var items = new List<EquipmentOutputStatisticsModel>();
            int index = 0;
            var maps = outputStatisticsList.GroupBy(x => x.EquipmentCode).Select(x => (x.Key, x.ToList())).ToList();
            foreach (var (key, list) in maps) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == key);
                if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var data = list.FirstOrDefault();
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;

                foreach (var item in list) {
                    if (m.EndMouldNumber > 0) {
                        m.MouldTimes += item.EndMouldNumber - item.StartMouldNumber ?? 0;
                    }
                }
                m.EquipmentName = info.Specification;
                m.MouldCavityNum = 12;
                m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                items.Add(m);
            }
            dto.Items = [.. items.OrderBy(x => x.EquipmentName)];
            var t2 = GetTrimOutputDto2(infos, outputStatisticsList, dic, ref index);
            if (!t2.None()) {
                dto.Items.AddRange(t2);
            }
            dto.Total = items.Sum(p => p.OutputQuantity);
            return dto;
        }

        /// <summary>
        /// 切边机
        /// </summary>
        /// <returns></returns>
        private static List<EquipmentOutputStatisticsModel> GetTrimOutputDto2(List<EquipmentInfoModel> infos,
                                                                              List<EquipmentOutputStatisticsEntity> outputStatisticsList,
                                                                              Dictionary<string, List<long>> dic,
                                                                              ref int index) {
            var typeids = dic["切边机"];
            var items = new List<EquipmentOutputStatisticsModel>();

            var maps = outputStatisticsList.GroupBy(x => x.EquipmentCode).Select(x => (x.Key, x.ToList())).ToList();
            foreach (var (key, list) in maps) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == key);
                if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var data = list.FirstOrDefault();
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;

                foreach (var item in list) {
                    if (m.EndMouldNumber > 0) {
                        m.MouldTimes += (item.EndMouldNumber - item.StartMouldNumber) ?? 0;
                    }
                }
                m.EquipmentName = info.Specification;
                m.MouldCavityNum = 20;
                m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                items.Add(m);
            }
            return items;
        }


        /// <summary>
        /// 堆叠
        /// </summary>
        /// <returns></returns>
        private static EquipmentOutputDto GetStackingOutputDto(List<EquipmentInfoModel> infos,
                                                               List<EquipmentOutputStatisticsEntity> outputStatisticsList,
                                                               Dictionary<string, List<long>> dic) {
            var dto = new EquipmentOutputDto();
            var typeids = dic["生产线"];
            var items = new List<EquipmentOutputStatisticsModel>();
            int index = 0;
            var maps = outputStatisticsList.GroupBy(x => x.EquipmentCode).Select(x => (x.Key, x.ToList())).ToList();
            foreach (var (key, list) in maps) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == key);
                if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var data = list.FirstOrDefault();
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;
                foreach (var item in list) {
                    if (m.EndNumber > 0) {
                        m.OutputQuantity += m.EndNumber.Value - m.StartNumber!.Value;
                    }
                }
                items.Add(m);
            }
            dto.Total = items.Sum(p => p.OutputQuantity);
            dto.Items = [.. items.OrderBy(x => x.EquipmentName)];
            return dto;
        }

        #endregion
        #region 产出推移图
        /// <summary>
        /// 获取设备产出推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<EquipmentOutputStatisticsModel>>> GetEquipmentOutputRunChart(RunChartParameter parameter) {
            var list = new List<EquipmentOutputStatisticsModel>();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList(AppHelper.QueryOrgId);

            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.EquipmentCode == parameter.EquipmentCode);
            var eosstatistics = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());
            if (parameter.Type == "FORMING") {
                list = GetFormingOutputRunChartDto(eosstatistics);
            } else if (parameter.Type == "TRIM") {
                list = GetTrimOutputRunChartDto(infoList, eosstatistics);
            } else if (parameter.Type == "STACKING") {
                list = GetStackingOutputRunChartDto(eosstatistics);
            }
            return Success(list);
        }

        /// <summary>
        /// 获取所有设备产出推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<OutputRunChartDto>>> GetAllEquipmentOutputRunChart(RunChartParameter parameter) {
            var list = new List<OutputRunChartDto>();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList();

            long orgid = AppHelper.QueryOrgId;
            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);





            var eosstatistics = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());
            var typeids = new List<long>();
            if (parameter.Type == "FORMING") {
                typeids = dic["成型机"];
            } else if (parameter.Type == "TRIM") {
                typeids = dic["冲切机"];
            } else if (parameter.Type == "STACKING") {
                typeids = dic["生产线"];
            }
            var maps = eosstatistics.GroupBy(x => x.Date).Select(p => (p.Key, p.ToList())).ToList();
            int index = 0;
            var items = new List<EquipmentOutputStatisticsModel>();
            foreach (var (key, itemlist) in maps) {
                var m = new EquipmentOutputStatisticsModel {
                    Id = index++,
                    Date = key
                };
                foreach (var item in itemlist) {
                    var info = infoList.FirstOrDefault(x => x.EquipmentCode == item.EquipmentCode);
                    if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                        continue;
                    }
                    if (item.EndMouldNumber > 0) {
                        if (parameter.Type == "STACKING") {
                            m.OutputQuantity += m.EndNumber - m.StartNumber ?? 0;
                        } else {
                            m.MouldTimes += item.EndMouldNumber.Value - item.StartMouldNumber!.Value;
                        }
                    }
                }

                if (parameter.Type == "FORMING") {
                    m.MouldCavityNum = 80;
                    if (m.MouldTimes > 0) {
                        m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                        items.Add(m);
                    }
                } else if (parameter.Type == "TRIM") {
                    m.MouldCavityNum = 12;
                    if (m.MouldTimes > 0) {
                        m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                        items.Add(m);
                    }
                } else if (parameter.Type == "STACKING") {
                    if (m.OutputQuantity > 0) {
                        items.Add(m);
                    }
                }
            }
            var dto = new OutputRunChartDto {
                EquipmentCode = "",
                EquipmentName = "",
                DataList = items
            };
            list.Add(dto);

            return Success(list);
        }
        /// <summary>
        /// 成型设备产出推移图
        /// </summary>
        /// <returns></returns>
        private static List<EquipmentOutputStatisticsModel> GetFormingOutputRunChartDto(List<EquipmentOutputStatisticsEntity> outputStatisticsList) {
            var items = new List<EquipmentOutputStatisticsModel>();
            int index = 0;
            foreach (var data in outputStatisticsList) {
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;
                if (m.EndMouldNumber > 0) {
                    m.MouldTimes = m.EndMouldNumber.Value - m.StartMouldNumber!.Value;
                }
                m.MouldCavityNum = 80;
                m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                items.Add(m);
            }
            return items;
        }

        /// <summary>
        /// 切边机设备产出推移图
        /// </summary>
        /// <returns></returns>
        private static List<EquipmentOutputStatisticsModel> GetTrimOutputRunChartDto(List<EquipmentInfoModel> infos, List<EquipmentOutputStatisticsEntity> outputStatisticsList) {

            var items = new List<EquipmentOutputStatisticsModel>();
            int index = 0;
            foreach (var data in outputStatisticsList) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == data.EquipmentCode);

                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;
                if (m.EndMouldNumber > 0) {
                    m.MouldTimes = m.EndMouldNumber.Value - m.StartMouldNumber!.Value;
                }
                m.EquipmentName = info!.Specification;
                m.MouldCavityNum = 12;
                m.OutputQuantity = m.MouldTimes * m.MouldCavityNum;
                items.Add(m);
            }
            return items;
        }
        /// <summary>
        /// 堆叠设备产出推移图
        /// </summary>
        /// <returns></returns>
        private static List<EquipmentOutputStatisticsModel> GetStackingOutputRunChartDto(List<EquipmentOutputStatisticsEntity> outputStatisticsList) {
            var items = new List<EquipmentOutputStatisticsModel>();
            int index = 0;
            foreach (var data in outputStatisticsList) {
                var m = data.Adapt<EquipmentOutputStatisticsModel>();
                m.Id = index++;
                if (m.EndNumber > 0) {
                    m.OutputQuantity = m.EndNumber.Value - m.StartNumber!.Value;
                }
                items.Add(m);
            }

            return items;
        }

        #endregion
        #region 电能
        /// <summary>
        /// 成型制程产出
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<EnergyConsumptionDto>> GetEnergyConsumptionDto(StatisticsParameter parameter) {
            var dto = new EnergyConsumptionDto();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList();
            long orgid = AppHelper.QueryOrgId;
            var whereExp = Expressionable.Create<EquipmentOutputStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);
            var eosstatistics = await _statistics.GetEquipmentOutputStatisticsList(whereExp.ToExpression());

            dto = GetEnergyConsumptionDto(infoList, eosstatistics, dic);
            return Success(dto);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static EnergyConsumptionDto GetEnergyConsumptionDto(List<EquipmentInfoModel> infos,
                                                                    List<EquipmentOutputStatisticsEntity> outputStatisticsList,
                                                                    Dictionary<string, List<long>> dic) {

            var dto = new EnergyConsumptionDto();
            var items = new List<EnergyConsumptionItem>();

            var typeids = dic["成型机"];
            var maps = outputStatisticsList.GroupBy(x => x.EquipmentCode).Select(x => (x.Key, x.ToList()));

            foreach (var item in maps) {
                var info = infos.FirstOrDefault(p => p.EquipmentCode == item.Key);
                if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var m = new EnergyConsumptionItem {
                    EquipmentName = info.EquipmentName,
                    EquipmentCode = info.EquipmentCode
                };
                foreach (var iem in item.Item2) {
                    if (iem.EndEnergy > 0) {
                        m.EnergyConsumption += iem.EndEnergy - iem.StartEnergy ?? 0;
                    }
                }
                items.Add(m);
            }
            dto.Items = items;
            dto.Total = items.Sum(p => p.EnergyConsumption);
            return dto;
        }
        #endregion
        #region 稼动率
        /// <summary>
        /// 成型机稼动率
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<UtilizationRateDto>> GetUtilizationRateDto(StatisticsParameter parameter) {
            var dto = new UtilizationRateDto();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            long orgid = AppHelper.QueryOrgId;
            var infoList = _equipmentclient.GetEquipmentInfoModelList(orgid);

            var eqswhereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            eqswhereExp.And(p => p.Date >= parameter.StartDate);
            eqswhereExp.And(p => p.Date <= parameter.EndDate);
            eqswhereExp.And(p => p.FactoryId == orgid);
            var eqstatistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(eqswhereExp.ToExpression());

            if (parameter.Type == "FORMING") {
                dto = GetUtilizationRateDto("成型机", infoList, eqstatistics, dic, typeList);
            } else if (parameter.Type == "TRIM") {
                dto = GetUtilizationRateDto("冲切机", infoList, eqstatistics, dic, typeList);
            } else if (parameter.Type == "AOI") {
                dto = GetUtilizationRateDto("AOI", infoList, eqstatistics, dic, typeList);
            }
            return Success(dto);
        }

        /// <summary>
        /// 成型机稼动率
        /// </summary>
        /// <returns></returns>
        private static UtilizationRateDto GetUtilizationRateDto(string typeName,
                                                                List<EquipmentInfoModel> infos,
                                                                List<EquipmentStatisticsEntity> statisticslist,
                                                                Dictionary<string, List<long>> dic,
                                                                List<EquipmentTypeEntity> typeList) {
            var dto = new UtilizationRateDto();
            var list = dic[typeName];
            if (typeName == "冲切机") {
                var st = dic["切边机"];
                list.AddRange(st);
            }
            var items = new List<EquipmentUtilizationRateStatisticsModel>();
            int index = 0;
            foreach (var info in infos) {
                if (info == null || !list.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var eqlist = statisticslist.Where(x => x.DeviceNo == info.EquipmentSign).ToList();
                if (eqlist.None()) {
                    continue;
                }
                var maps = eqlist.GroupBy(x => x.Date).Select(x => (x.Key, x.ToList())).ToList();
                var m = new EquipmentUtilizationRateStatisticsModel {
                    ActualWorkingHour = 0,
                    StandardWorkingHour = 0,
                    EquipmentName = (typeName == "冲切机" || typeName == "切边机") ? info.Specification : info.EquipmentName,
                    EquipmentCode = info.EquipmentCode,
                    Id = index++
                };
                items.Add(m);
                foreach (var (key, itemlist) in maps) {
                    foreach (var es in itemlist) {
                        decimal st = 0;
                        if (es.Classes?.StartsWith('8') ?? false) {
                            st = (decimal)(info.DayStandardHour > 0 ? info.DayStandardHour : 12);
                        } else {
                            st = (decimal)(info.NightStandardHour > 0 ? info.NightStandardHour : 12);
                        }
                        if (es.ActualWorkingHour > st) {
                            m.ActualWorkingHour += st;
                        } else {
                            m.ActualWorkingHour += es.ActualWorkingHour ?? 0;
                        }
                        m.StandardWorkingHour += st;
                    }
                }
                m.UtilizationRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 2);
            }
            dto.Items = [.. items.OrderBy(x => x.EquipmentName)];
            if (typeName == "成型机") {
                var others = GetOtherUtilizationRateDto(infos, statisticslist, dic, ref index);
                if (!others.None()) {
                    dto.Items.AddRange(others);
                }
            }
            decimal sum = items.Sum(m => m.StandardWorkingHour) ;
            decimal acwhour = items.Sum(x => x.ActualWorkingHour ?? 0);
            if (sum > 0) {
                dto.Total = Math.Round(acwhour / sum * 100, 1);
            }
            return dto;
        }
        /// <summary>
        /// 成型机稼动率
        /// </summary>
        /// <returns></returns>
        private static List<EquipmentUtilizationRateStatisticsModel> GetOtherUtilizationRateDto(List<EquipmentInfoModel> infos,
                                                                                                List<EquipmentStatisticsEntity> statisticslist,
                                                                                                Dictionary<string, List<long>> dic,
                                                                                                ref int index) {
            var list = dic["生产线"];
            var items = new List<EquipmentUtilizationRateStatisticsModel>();
            foreach (var info in infos) {
                if (info == null || !list.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var eqlist = statisticslist.Where(x => x.DeviceNo == info.EquipmentSign).ToList();
                if (eqlist.None()) {
                    continue;
                }
                var maps = eqlist.GroupBy(x => x.Date).Select(x => (x.Key, x.ToList())).ToList();
                var m = new EquipmentUtilizationRateStatisticsModel {
                    ActualWorkingHour = 0,
                    StandardWorkingHour = 0,
                    EquipmentName = info.EquipmentName,
                    EquipmentCode = info.EquipmentCode,
                    Id = index++
                };
                items.Add(m);
                foreach (var (key, itemlist) in maps) {
                    foreach (var es in itemlist) {
                        decimal st = 0;
                        if (es.Classes?.StartsWith('8') ?? false) {
                            st = (decimal)(info.DayStandardHour > 0 ? info.DayStandardHour : 12);
                        } else {
                            st = (decimal)(info.NightStandardHour > 0 ? info.NightStandardHour : 12);
                        }
                        if (es.ActualWorkingHour > st) {
                            m.ActualWorkingHour += st;
                        } else {
                            m.ActualWorkingHour += es.ActualWorkingHour ?? 0;
                        }
                        m.StandardWorkingHour += st;
                    }
                }
                m.UtilizationRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 2);
            }

            return items;
        }

        #endregion
        #region  稼动率推移图
        /// <summary>
        /// 获取设备稼动率推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<EquipmentUtilizationRateStatisticsModel>>> GetEquipmentUtilizationRateRunChart(RunChartParameter parameter) {
            var list = new List<EquipmentUtilizationRateStatisticsModel>();

            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList();
            var info = infoList.FirstOrDefault(x => x.EquipmentCode == parameter.EquipmentCode);
            if (info == null) {
                return Fail(list, "数据异常");
            }
            var whereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.DeviceNo == info!.EquipmentSign);
            var statistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(whereExp.ToExpression());

            var type = typeList.FirstOrDefault(p => p.Id == info?.EquipmentTypeId);
            decimal st = type?.StandardWorkingHour ?? 12;
            DateTime current = parameter.StartDate;
            while (current <= parameter.EndDate) {
                var m = new EquipmentUtilizationRateStatisticsModel {
                    ActualWorkingHour = 0,
                    StandardWorkingHour = 0,
                    EquipmentName = info?.EquipmentName ?? "",
                    EquipmentCode = info?.EquipmentCode ?? "",
                    Date = current
                };
                var itemlist = statistics.Where(x => x.Date == current).ToList();
                if (!itemlist.None()) {
                    foreach (var es in itemlist) {
                        if (es.ActualWorkingHour > st) {
                            m.ActualWorkingHour += st;
                        } else {
                            m.ActualWorkingHour += es.ActualWorkingHour ?? 0;
                        }
                        m.StandardWorkingHour += st;
                    }
                }
                if (m.ActualWorkingHour > 0) {
                    m.UtilizationRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                    m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 1);
                }
                list.Add(m);
                current = current.AddDays(1);
            }
            return Success(list);
        }
        /// <summary>
        /// 获取设备制程平均稼动率推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<UtilizationRateRunChartDto>>> GetAllEquipmentUtilizationRateRunChart(RunChartParameter parameter) {
            var list = new List<UtilizationRateRunChartDto>();
            long orgid = AppHelper.QueryOrgId;
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            var infoList = _equipmentclient.GetEquipmentInfoModelList(orgid);

            var whereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            whereExp.And(p => p.Date >= parameter.StartDate);
            whereExp.And(p => p.Date <= parameter.EndDate);
            whereExp.And(p => p.FactoryId == orgid);
            var statistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(whereExp.ToExpression());
            var typeids = new List<long>();
            if (parameter.Type == "FORMING") {
                typeids = dic["成型机"];
            } else if (parameter.Type == "TRIM") {
                typeids = dic["冲切机"];
                var st = dic["切边机"];
                if (!st.None()) {
                    typeids.AddRange(st);
                }
            } else if (parameter.Type == "STACKING") {
                typeids = dic["生产线"];
            } else if (parameter.Type == "AOI") {
                typeids = dic["AOI"];
            }
            var maps = statistics.GroupBy(x => x.Date).Select(x => (x.Key, x.ToList())).ToList();
            var dto = new UtilizationRateRunChartDto() { DataList = [] };

            DateTime current = parameter.StartDate;
            while (current <= parameter.EndDate) {
                var m = new EquipmentUtilizationRateStatisticsModel {
                    ActualWorkingHour = 0,
                    Date = current,
                };
                var itemlist = statistics.Where(x => x.Date == current).ToList();
                foreach (var info in infoList) {
                    if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                        continue;
                    }
                    var type = typeList.FirstOrDefault(x => x.Id == info.EquipmentTypeId);
                    var datalist = itemlist.Where(x => x.DeviceNo == info.EquipmentSign).ToList();
                    if (datalist.None()) {
                        continue;
                    }
                    var st = type?.StandardWorkingHour ?? 12;
                    foreach (var es in datalist) {
                        if (es.ActualWorkingHour > st) {
                            m.ActualWorkingHour += st;
                        } else {
                            m.ActualWorkingHour += es.ActualWorkingHour ?? 0;
                        }
                        m.StandardWorkingHour += st;
                    }
                }
                m.UtilizationRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 1);
                dto.DataList.Add(m);
                current = current.AddDays(1);
            }
            list.Add(dto);
            return Success(list);
        }

        #endregion

        #region 利用率
        /// <summary>
        /// 成型机利用率
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<UsageRateDto>> GetUsageRateDto(StatisticsParameter parameter) {
            var dto = new UsageRateDto();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            long orgid = AppHelper.QueryOrgId;
            var infoList = _equipmentclient.GetEquipmentInfoModelList(orgid);

            var eqswhereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            eqswhereExp.And(p => p.Date >= parameter.StartDate);
            eqswhereExp.And(p => p.Date <= parameter.EndDate);
            eqswhereExp.And(p => p.FactoryId == orgid);
            var eqstatistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(eqswhereExp.ToExpression());

            dto = GetUsageRateDto(infoList, eqstatistics, dic, typeList, parameter.StartDate, parameter.EndDate);
            return Success(dto);
        }
        /// <summary>
        /// 成型机利用率
        /// </summary>
        /// <returns></returns>
        private static UsageRateDto GetUsageRateDto(List<EquipmentInfoModel> infos,
                                                    List<EquipmentStatisticsEntity> statisticslist,
                                                    Dictionary<string, List<long>> dic,
                                                    List<EquipmentTypeEntity> typeList,
                                                    DateTime startDate,
                                                    DateTime endDate) {
            var dto = new UsageRateDto();
            var list = dic["成型机"];
            var ottypeids = dic["生产线"];
            list.AddRange(ottypeids);

            var items = new List<EquipmentUtilizationRateStatisticsModel>();

            int index = 0;
            decimal actualWorkingHour = 0;
            foreach (var info in infos) {
                if (info == null || !list.Contains(info.EquipmentTypeId)) {
                    continue;
                }
                var m = new EquipmentUtilizationRateStatisticsModel {
                    ActualWorkingHour = 0,
                    StandardWorkingHour = 0,
                    EquipmentName = info.EquipmentName,
                    EquipmentCode = info.EquipmentCode,
                    Id = index++
                };
                items.Add(m);
                DateTime current = startDate;
                while (current <= endDate) {
                    var itemlist = statisticslist.Where(x => x.DeviceNo == info.EquipmentSign && x.Date == current).ToList();
                    foreach (var es in itemlist) {
                        decimal st = 0;
                        if (es.Classes?.StartsWith('8') ?? false) {
                            st = info.DayStandardHour > 0 ? info.DayStandardHour : 12;
                        } else {
                            st = info.NightStandardHour > 0 ? info.NightStandardHour : 12;
                        }
                        if (es.ActualWorkingHour > st) {
                            m.ActualWorkingHour += st;
                        } else {
                            m.ActualWorkingHour += es.ActualWorkingHour ?? 0;
                        }
                    }
                    if (info.DayStandardHour > 0) {
                        m.StandardWorkingHour += info.DayStandardHour;
                    } else {
                        m.StandardWorkingHour += 12;
                    }
                    if (info.NightStandardHour > 0) {
                        m.StandardWorkingHour += info.NightStandardHour;
                    } else {
                        m.StandardWorkingHour += 12;
                    }
                    current = current.AddDays(1);
                }
                actualWorkingHour += (decimal)m.ActualWorkingHour;
                if (m.StandardWorkingHour == 0) {
                    m.UsageRate = 0;
                    m.ActualWorkingHour = 0;
                } else {
                    m.UsageRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                    m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 2);
                }
            }
            dto.Items = [.. items.OrderBy(x => x.EquipmentName)];

            var standardWorkingHour = Math.Round(items.Sum(x => x.StandardWorkingHour), 2);
            actualWorkingHour = Math.Round(actualWorkingHour, 2);
            if (standardWorkingHour >0) {
                dto.Total = Math.Round(actualWorkingHour / standardWorkingHour * 100, 1);
            }
           
            return dto;
        }
        /// <summary>
        /// 成型机利用率推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<EquipmentUtilizationRateStatisticsModel>>> GetUsageRateRunChart(RunChartParameter parameter) {
            var list = new List<EquipmentUtilizationRateStatisticsModel>();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);

            var infoList = _equipmentclient.GetEquipmentInfoModelList(AppHelper.QueryOrgId);
            var info = infoList.FirstOrDefault(p => p.EquipmentCode == parameter.EquipmentCode);
            if (info == null) {
                return Fail(list, "数据异常");
            }
            var eqswhereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            eqswhereExp.And(p => p.Date >= parameter.StartDate);
            eqswhereExp.And(p => p.Date <= parameter.EndDate);
            eqswhereExp.And(p => p.DeviceNo == info.EquipmentSign);
            var eqstatistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(eqswhereExp.ToExpression());

            var type = typeList.FirstOrDefault(p => p.Id == info.EquipmentTypeId);

            DateTime current = parameter.StartDate;
            while (current <= parameter.EndDate) {
                var m = new EquipmentUtilizationRateStatisticsModel() {
                    ActualWorkingHour = 0,
                    Date = current
                };
                var eqlist = eqstatistics.Where(x => x.Date == current).ToList();

                if (!eqlist.None()) {
                    foreach (var item in eqlist) {
                        decimal st = 0;
                        if (item.Classes?.StartsWith('8') ?? false) {
                            st = st > 0 ? info.DayStandardHour : 12;
                        } else {
                            st = st > 0 ? info.NightStandardHour : 12;
                        }
                        if (item.ActualWorkingHour > st) {
                            m.ActualWorkingHour += st;
                        } else {
                            m.ActualWorkingHour += item.ActualWorkingHour ?? 0;
                        }
                    }
                }
                if (info.DayStandardHour > 0) {
                    m.StandardWorkingHour += info.DayStandardHour;
                } else {
                    m.StandardWorkingHour += 12;
                }
                if (info.NightStandardHour > 0) {
                    m.StandardWorkingHour += info.NightStandardHour;
                } else {
                    m.StandardWorkingHour += 12;
                }
                m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 2);
                m.UsageRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                list.Add(m);
                current = current.AddDays(1);
            }

            return Success(list);
        }

        /// <summary>
        /// 成型机利用率推移图
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult<List<UsageRateRunChartDto>>> GetAllUsageRateRunChart(RunChartParameter parameter) {
            var list = new List<UsageRateRunChartDto>();
            var typeList = await _equipmentclient.GetEquipmentTypeListAsync();
            var dic = GetEquipmentTypeDic(typeList);
            long orgid = AppHelper.QueryOrgId;
            var infoList = _equipmentclient.GetEquipmentInfoModelList(orgid);

            var eqswhereExp = Expressionable.Create<EquipmentStatisticsEntity>();
            eqswhereExp.And(p => p.Date >= parameter.StartDate);
            eqswhereExp.And(p => p.Date <= parameter.EndDate);
            eqswhereExp.And(p => p.FactoryId == orgid);

            var eqstatistics = await _statistics.GetEquipmentUtilizationRateStatisticsList(eqswhereExp.ToExpression());

            var maps = eqstatistics.GroupBy(x => x.Date).Select(x => (x.Key, x.ToList())).ToList();
            var typeids = dic["成型机"];
            var ottypeids = dic["生产线"];
            typeids.AddRange(ottypeids);


            var items = new List<EquipmentUtilizationRateStatisticsModel>();

            DateTime current = parameter.StartDate;
            while (current <= parameter.EndDate) {
                var m = new EquipmentUtilizationRateStatisticsModel() {
                    ActualWorkingHour = 0,
                    Date = current
                };
                foreach (var info in infoList) {
                    if (info == null || !typeids.Contains(info.EquipmentTypeId)) {
                        continue;
                    }
                    var eqlist = eqstatistics.Where(x => x.Date == current && x.DeviceNo == info.EquipmentSign).ToList();

                    if (info.DayStandardHour > 0) {
                        m.StandardWorkingHour += info.DayStandardHour;
                    } else {
                        m.StandardWorkingHour += 12;
                    }
                    if (info.NightStandardHour > 0) {
                        m.StandardWorkingHour += info.NightStandardHour;
                    } else {
                        m.StandardWorkingHour += 12;
                    }

                    if (!eqlist.None()) {
                        foreach (var item in eqlist) {
                            decimal st = 0;
                            if (item.Classes?.StartsWith('8') ?? false) {
                                st = st > 0 ? info.DayStandardHour : 12;
                            } else {
                                st = st > 0 ? info.NightStandardHour : 12;
                            }
                            if (item.ActualWorkingHour > st) {
                                m.ActualWorkingHour += st;
                            } else {
                                m.ActualWorkingHour += item.ActualWorkingHour ?? 0;
                            }
                        }
                    }
                }
                m.StandardWorkingHour = Math.Round(m.StandardWorkingHour, 2);
                m.ActualWorkingHour = Math.Round(m.ActualWorkingHour ?? 0, 2);
                m.UsageRate = Math.Round((m.ActualWorkingHour ?? 0) / m.StandardWorkingHour * 100, 1);
                items.Add(m);
                current = current.AddDays(1);
            }

            var dto = new UsageRateRunChartDto {
                EquipmentName = "成型机整体利用率",
                EquipmentCode = "成型机整体利用率",
                DataList = items
            };

            list.Add(dto);
            return Success(list);
        }

        #endregion



        #region 累计订单
        /// <summary>
        /// 累计订单数量
        /// </summary>
        /// <returns></returns>
        private async Task<CumulativeOrderQuantityDto> GetCumulativeOrderQuantityDto() {
            var dto = new CumulativeOrderQuantityDto();
            var orderlist = await _workOrder.GetOrderListAsync(p => p.OrderQuantity > p.Quantity);
            var items = new List<CumulativeItem>();
            foreach (var order in orderlist) {
                //var rp = reportWorkRecords.FirstOrDefault(x => x.EquipmentCode == eqcode.Item2.EquipmentCode);
                var itm = new CumulativeItem {
                    OrderCode = order.OrderCode,
                    OrderQuantity = order.OrderQuantity,
                    ProductName = order.ProductName
                };
                items.Add(itm);
            }
            dto.Items = items;
            dto.Total = items.Sum(t => t.OrderQuantity);
            return dto;
        }
        #endregion
        #region 累计入库数量
        /// <summary>
        /// 累计入库数量
        /// </summary>
        /// <returns></returns>
        private async Task<CumulativeStockInQuantityDto> GetCumulativeStockInQuantityDtoAsync(List<EquipmentInfoModel> infos,
                                                                             Dictionary<string, List<long>> dic,
                                                                             CumulativeOrderQuantityDto orderDto) {
            var dto = new CumulativeStockInQuantityDto();
            var list = dic["AOI"];
            var aoiinfos = infos.Where(p => list.Contains(p.EquipmentTypeId)).ToList();
            var codes = aoiinfos.ConvertAll(x => x.EquipmentCode);
            //开工数据
            var swrecordList = await _workOrder.GetStartWorkRecordListAsync(p => codes.Contains(p.EquipmentCode));
            //报工数据
            var wrecordList = await _workOrder.GetReportWorkRecordListAsync(p => codes.Contains(p.EquipmentCode));


            foreach (var data in orderDto.Items) {
                var swinfos = swrecordList.Where(p => p.OrderCode == data.OrderCode).ToList();
                if (swinfos.None()) {
                    continue;
                }
                foreach (var swinfo in swinfos) {
                    var rep = wrecordList.FirstOrDefault(p => p.ReportWorkTime == swinfo.StartWorkTime && p.EquipmentCode == swinfo.EquipmentCode);
                    if (rep == null) {
                        continue;
                    }
                    data.StockInQuantity += rep.MouldNumber = swinfo.MouldNumber;
                }
            }
            dto.Items = orderDto.Items;
            dto.Total = orderDto.Items.Sum(p => p.StockInQuantity);
            return dto;
        }
        #endregion



        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static Dictionary<string, List<long>> GetEquipmentTypeDic(List<EquipmentTypeEntity> typelist) {
            var dic = new Dictionary<string, List<long>>();
            var temps = typelist.Where(p => p.ParentId == 0).ToList();
            foreach (var item in temps) {
                var items = GetChildEquipmentTypeList(item.Id, typelist);
                if (items.None()) {
                    continue;
                }
                items.Add(item.Id);
                dic[item.Name] = items;
            }
            return dic;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static List<long> GetChildEquipmentTypeList(long parentId, List<EquipmentTypeEntity> typelist) {
            var list = new List<long>();
            var temps = typelist.Where(p => p.ParentId == parentId).ToList();
            foreach (var item in temps) {
                list.Add(item.Id);
                var items = GetChildEquipmentTypeList(item.Id, typelist);
                if (!items.None()) {
                    list.AddRange(items);
                }
            }
            return list;
        }
    }
}
